Translated by visionNoob, KNU https://github.com/insurgent92/CS231N_17_KOR_SUB
자 12시가 지났군요 시작합니다.
우선 지난시간에 배운 내용을 복습하겠습니다.
지난시간에 Nerural networks를 학습 시킬 때 필요한 여러가지 중요한 것들을 배웠습니다.
지난 시간에 배운 내용을 다시 한번 살펴 본 뒤에 몇 가지 더 배워보겠습니다.
우선 공지사항을 몇 가지 전달합니다.
우선 과제 1의 마감기한이 종료되었습니다. 여러분 모두 잘 제출했길 바랍니다.
다들 잘 했나요? 과제 1은 체점 중에 있습니다.
그리고 두 번째는 프로젝트 제안서 제출은 금일 11:59 PM 까지 입니다.
오늘 까지 꼭 제출 해 주시기 바랍니다. 자세한 사항은 web과 Piazza에서 확인바랍니다.
그리고 과제 2가 나왔습니다. 제출까지 1주일정도의 기간이 남았습니다.
과제 2는 우리 수업에서 가장 오래 걸리는 과제 입니다. 그러니 서둘러 진행 하는 것을 추천드립니다.
그리고 과제 2를 하실때 팁을 드리자면 현재 대다수가 Googld Cloud를 쓰고 계신데
Googld Cloud에서 instances를 사용하지 않을 시에는 반드시 종료시켜 줘야 합니다. 아니면 요금이 계속 지불됩니다.
여러분들이 쿠폰을 너무 많이 씁니다.
instance에서 아무 작업도 하지 않더라도 켜져 있으면 요금이 부과됩니다.
그러니 사용하지 않으면 반드시 종료시켜 줘야 합니다.
여기 제 대쉬보드 화면인데, 이런 식으로 확실하게 STOP 버튼을 눌러줘야 합니다.
매일 매일 이렇게 종료 시켜 주시기 바랍니다.
그리고 Googld Cloud를 사용할 때 아셔하 할 것은 GPU를 쓰는 것이 CPU보다 더 비싸다는 것입니다.
GPU를 쓰시면 어림잡아 시간당 거의 1 달러를 사용하게 됩니다. 상당히 가격이 높습니다.
CPU instances는 조금 더 쌉니다. 추천 드리는 방법은 GPU instance는 GPU가 필요할 때만 쓰는 것입니다.
가령 과제 2를 하실 때 대게는 CPU만 있으면 됩니다. 따라서 CPU instance만 사용하면 됩니다.
하지만 과제2의 마지막 문제를 풀때 사용하는 Tensorflow와 PyTorch는 GPU가 필요합니다.
CPU와 GPU instance를 각각 만들고 정말 필요할 때만 GPU instance를 사용하시길 권장드립니다.
그러니 비용이 얼마나 지불되는 지를 모니터링 하면서 지나치게 지불되는 것을 주의하시기 바랍니다.
공지사항 관련한 질문사항 있나요?
질문있나요?
[학생이 질문]
RAM을 얼마나 사용해야 하냐고 하셨는데
과제용으로는 8~16기가면 충분합니다.
CPU나 RAM을 너무 많이 추가하면 돈이 많이 듭니다.
CPU는 2~4개를 쓰고 RAM은 8~16 기가를 쓰시면 과제 하실 때 충분한 사양입니다.
지난 시간 내용을 복습해 보면 Activation function을 배웠습니다.
지난 시간에 다양한 Activation Function과 각각의 특성을 배웠습니다.
10년 전에는 sigmoid가 아주 유명했습니다. 하지만 Vanishing gradients가 생기는 문제가 있었죠 tanh도 마찬가지 이구요
그래서 요즘은 대부분 ReLU를 씁니다. 일반적인 네트워크에서 가장 잘 동작하는 녀석입니다.
그래서 가중치 초기화에 대해서도 배웠습니다.
가중치가 지나치게 작으면 activatiom이 사라집니다.
작은 값이 여러 번 곱해지기 때문에 점점 0이 되는 것이었습니다.
결국 모든 값이 0이 되고 학습은 일어나지 않습니다.
반면에 가중치가 너무 큰 값으로 초기화되면 그 값이 또 계속 곱해질 것이고 결국은 터져버릴 것입니다(explode).
이 경우에도 학습이 일어나지 않을 것입니다.
Xavier/MSRA(HE) Initialzation 같은 방법으로 초기화를 잘 시켜주면 Activation의 분포를 좋게 유지시킬 수 있습니다.
명심해야 할 점은 위의 것들이 Network가 깊어지면 깊어질 수록 더 중요하다는 것입니다.
Network가 깊어지면 깊어질수록 가중치를 더 많이 곱하게 되기 때문입니다.
그리고 데이터 전처리가 있었죠. CNN은 zero-mean을 주로 사용하며, 그 밖에 zero-mean, unit variance에 대해서도 배웠습니다.
제가 여러분에게 왜 그걸 해야하는 지를 좀 더 직관적으로 말씀 드리겠습니다.
자 여기에서 우리는 Binary classification 문제를 풉니다. 빨간/파란 점들을 나누는 것입니다.
왼쪽의 경우 not normalized/centered 데이터 입니다.
이 경우에도 물론 classification이 가능하지만 선이 조금만 움직여도 classification이 잘 되지 않습니다.
왼쪽의 예시가 의미하는 것은 손실 함수가 아주 약간의 가중치 변화에도 엄청 예민하다는 것입니다.
왼쪽의 경우 동일한 함수를 쓰더라도 학습 시키기 아주 어렵습니다. 재차 말씀드리지만 Loss가 파라미터에 너무 민감하기 때문입니다.
반면 오른쪽은 데이터의 중심을 원점에 맞추고(zero-center), Unit variance로 만들어 준 경우 입니다.
오른쪽에서의 선이 조금씩 흔들리는 경우는 보면 손실 함수는 이런 가중치의 변동에 덜 민감함을 알 수 있습니다.
이 경우가 최적화가 더 쉽습니다. 학습이 더 잘되는 것입니다.
그리고 이는 Linear classification의 경우에만 국한되는 것이 아닙니다.
Neural network 내부에도 다수의(interleavings) linear classifer가 있다고 생각할 수 있습니다.
이 경우에도 Neural network의 입력이 zero-centered가 아니고 Unit variance가 아닌 경우라면
레이어의 Weight matrix가 아주 조금만 변해도 출력은 엄청 심하게 변하게 됩니다. 이는 학습을 어렵게 합니다.
이를 통해 왜 nomalization가 중요한지를 좀 더 직관적으로 이해하실 수 있을 것입니다.
자 우리는 Normalization이 엄청 중요하다는 것을 알고 있기 때문에 batch normalization도 배웠습니다.
이는 actications이 zero mean과 unit variance가 될 수 있도록 레이어를 하나 추가하는 방법이었습니다.
제가 이 슬라이드에 batch normalization 수식을 다시한번 적어 봤습니다.
이 슬라이드를 보면 과제 2를 하실 때 수월할 것입니다.
BN에서는 forward pass 시에 미니배치에서의 평균과 표준편차를 계산해서 Normalization을 수행했습니다.
그리고 레이어의 유연한 표현성(expressivity)을 위해서 scale, shift 파라미터를 추가했습니다.
과제 2를 하실때 이를 참고하시기 바랍니다.
그리고 학습 과정을 다루는 방법도 배웠습니다. 학습 도중 Loss curve가 어떻게 보여야 하는지도 말이죠
여기 예제 네트워크가 있습니다. 주말동안 한번 돌려봤습니다. 저는 학습을 진행할 때 이런 식으로 진행합니다.
가운데 그래프는 시간에 따른 Loss 값을 나타냅니다. 네트워크가 Loss를 줄이고 있으면 잘 하고 있는 것이죠
맨 오른쪽 그래프를 보면 X는 시간축이고 Y는 성능 지표입니다. Training/Validation set의 성능지표를 나타냅니다.
이를 해석해보면 Training set의 성능을 계속 올라가죠 Loss도 계속 내려갑니다. 하지만 validation은 침체하고 있습니다.
이런 경우는 overfititing이라고 할 수 있겠습니다. 추가적인 regularization이 필요한 것입니다.
그리고 이전 강의에서 hyperparameter search도 배웠습니다.
네트워크에는 무수히 많은 하이퍼파라미터가 존재합니다. 이를 올바르게 잘 선택하는 것은 상당히 중요합니다.
그리고 grid search와 random search를 배웠습니다. 이론상 random search가 더 좋았습니다.
왜냐하면 성능이 특정 하이퍼파라미터에 의해 크게 좌우될 때 그 파라미터를 좀 더 넓은 범위로 탐색할 수 있기 때문입니다.
그리고 하이퍼파라미터 최적화 시에 coarse search 이후 fine search를 한다고 배웠습니다.
처음에는 하이퍼파라미터를 조금 더 넒은 범위에서 찾습니다. Interation도 작게 줘서 학습시켜봅니다.(coarse)
그리고 결과가 좋은 범위로 좁히는 것입니다.
그리고 iterations를 조금 더 돌면서 더 작은 범위를 다시 탐색합니다. (fine search)
적절한 하이퍼파라미터를 찾을 때 까지 이 과정을 반복합니다.
가장 중요한 점은 coarse range를 설정할 때 가능한 최대한 넓은 범위를 설정해 줘야 한다는 것입니다.
그 범위가 하이퍼파라미터 범위의 끝에서 끝까지 다 살펴볼 수 있도록 할수록 좋습니다. 충분히 넓은 범위를 사용해야 합니다.
질문 있나요?
[학생이 질문]
질문은 보통 하이퍼파라미터를 몇 개씩 선택하는지 입니다.
여기 예제에서는 2개 인데 보통은 2개보단 많습니다.
그 선택은 모델에 따라 다릅니다. 선택한 하이퍼파라미터의 수가 많을 수록 기하급수적으로 경우의 수가 늘어납니다.
때문에 한번에 너무 많이 할 수 는 없습니다.
또 이는 여러분이 얼마나 많은 자원을 학습에 사용할 수 있는지도 중요합니다.
이는 사람마다 다르고 실험마다 다릅니다.
저같은 경우 두 세가지 정도를 고르는 편이고 많아도 네 가지 정도만 선택합니다. 그 이상이면 out of control이 되버립니다.
일반적으로는 Learning rate가 가장 중요합니다. Learning rate를 가장 먼저 선택해 놔야만 합니다.
regularization, learning rate decay, model size 같은 것들은 LR보단 덜 중요합니다.
Block Coordinate Descent(BCD) 같은 방법을 쓸 수도 있습니다.
가령, 우선 Learning rate를 정해놓은 다음에 다양한 모델 사이즈를 시도해 보는 것입니다.
이 방법을 쓰면 기하급수적으로 늘어나는 Search space를 조금은 줄일 수 있습니다.
하지만 이 방법은 정확히 어떤 순서로 어떻게 찾아야 할지 정해야 하는 것이 가장 큰 문제입니다.
다른 질문 있으신가요?
[학생이 질문]
질문은 우리가 어떤 하이퍼파리미터 값을 변경할 시에 다른 하이퍼파라미터 의 최적 값이 변해버리는 경우가 빈번하냐는 것입니다.
그런 일이 가끔 발생하긴 합니다. Learning rates가 이런 문제에 덜 민감함에도 실제로 이런 일이 발생하곤 합니다.
Leraning rates가 좋은 범위 내에 속했으면 하지만 보통은 optimal 보다는 작은 값이고 학습 속도가 길어지곤 합니다.
이런 경우에는, 오늘 배우게 될, 더 좋은(fancier) 최적화 방법을 사용하면 모델이 learning rate에 덜 민감하도록 할 수 있습니다.
다른 질문 있으신가요?
[학생이 질문]
질문은 Learning rate를 작게 하고 Epoch을 늘리면 어떤 일이 발생하는지 입니다.
그렇게 되면 엄청 오래 걸리겠죠
[학생이 질문]
Learning rates를 낮추고 오랫동안 학습시키게 되면 이론적으로는 항상 동작하는 것이 맞습니다.
하지만 실제로는 Learning rate가 0.01이냐 0.001이냐는 상당히 중요한 문제가 됩니다.
여러분이 적절한 Leraning rate를 찾으면 6시간, 12시간 또는 하루면 학습을 다 시킬 수 있을 텐데
그런데 여러분이 엄청 조심스러워서 Learning rate를 10배, 100배 줄여 버라면 하루면 끝나는 것이 100일이 걸릴수 있습니다.
그럼 세 달이 걸리게 되는 것입니다. 좋지 않은 경우입니다.
보통 컴퓨터과학 분야를 배울때 이런 constants(10배 100배)를 중요하게 다루지 않는 경향이 있는데
당신은 실제로 훈련하는 것에 대해 생각하고 있습니다. 그 constants은 많은 문제가됩니다.
다른 질문 있나요?
[학생이 질문]
질문은 Low learning rate를 주게되면 local optima에 빠질 수 있지 않냐는 것입니다.
이는 직관적으로는 그럴 수 있겠지만 실제로 그런 일은 많이 발생하지는 않습니다.
이에 관한 내용을 오늘 잠시 뒤에 다시 배울 것입니다.
오늘은 Neural networks를 학습시킬 때 필요한 흥미롭고 아주 중요한 문제를 몇 가지 배워보도록 하겠습니다.
제가 이전에 더 강력한 최적화 알고리즘이 있다고 앞서 몇 번 언급한 적이 있었습니다.
오늘은 사람들이 많이 사용하는 그 강력한 알고리즘들에 대해서 좀 더 자세히 알아보는 시간이 되겠습니다.
지난 강의에 Regularization에 대해서도 조금 배웠었죠
네트워크의 Train/Test Error 간의 격차를 줄이고자 사용하는 추가적인 기법입니다.
Neural Network에서 실제로 사람들이 사용하고 있는 Regularization 전략에 대해서 다뤄보도록 하겠습니다.
그리고 Transfer learning에 대해서도 배울 것입니다.
원하는 양 보다 더 적은 데이터만을 가지고 있을때 사용할 수 있는 방법입니다.
지난 강의를 돌이켜보면 Neural network에서 가장 중요한 것은 바로 최적화 문제 였다는 것을 알 수 있습니다.
Nerwork의 가중치에 대해서 손실 함수를 정의해 놓으면 이 손심 함수는 그 가중치가 얼마나 좋은지 나쁜지를 알려줍니다.
그리고 우리는 손심 함수가 가중치에 대한 "산(landscape)"이라고 상상해 볼 수 있을 것입니다.
여기 맨 오른쪽 사진에 간단한 예제를 가져왔습니다. X/Y축은 두 개의 가중치를 의미합니다.
그리고 각 색은 Loss의 값을 나타냅니다.
이 오른쪽의 2차원의 문제를 두 개의 가중치 W_1과 W_2를 최적화 시키는 문제라고 생각해 봅시다.
우리의 목적은 가장 붉은색인 지점을 찾는 것입니다. 즉 가장 낮은 Loss를 가진 가중치를 찾는 것이죠.
자 지금까지 배운 것을 생각해 봅시다. 가장 간단한 최적화 알고리즘은 바로 Stochastic Gradient Descent 입니다.
이 세 줄로 된 엄청 간단한 알고리즘이죠
우선 미니 배치 안의 데이터에서 Loss를 계산합니다.
그리고 'Gradient 의 반대 방향" 을 이용해서 파라미터 벡터를 업데이트합니다.
반대 방향인 이유는 손실 함수를 내려가는 방향 이어야 하기 때문입니다.
이 단계를 계속 반복하면 결국 붉은색 지역으로 수렴할 것이고 Loss가 낮을 것입니다.
하지만 이 심플한 알고리즘을 실제로 사용하게 되면 몇 가지 문제에 봉착하고 맙니다.
SGD의 문제점 중 하나는,
가령 우리의 손실함수가 이런 식으로 생겼다고 생각해 봅시다. 여기에 똑같이 W_1과 W_2가 있다고 해봅시다.
둘중 어떤 하나는 업데이트를 해도 손실 함수가 아주 느리게 변합니다.
즉, 수평 축의 가중치는 변해도 Loss가 아주 천천히 줄어듭니다.
다시 말해 Loss는 수직 방향의 가중치 변화에 훨씬 더 민감하게 반응하는 것입니다.
다시 말해 현재 지점에서 Loss는 bad condition number를 지니고 있다고 말할 수 있을 것입니다.
이 지점의 Hessian maxrix의 최대/최소 singular values 값의 비율이 매우 안좋다는 뜻입니다.
이를 좀 더 직관적으로 이해해보면 우선 Loss가 taco shell 같은 모양입니다.
한 방향으로는 엄청나게 민감한 반면에 다른 방향으로는 덜 민감한 상태에 있는 것입니다.
그렇다면 질문입니다. 이런 상황에서 SGD으로 학습이 되는 과정은 어떤 모습일까요?
손실 함수가 이런 식으로 생긴 환경에서 SGD를 수행하면, 이런 특이한 지그재그 형태를 볼 수 있을 것입니다.
왜냐하면 이런 함수에서는 gradient의 방향이 고르지 못하기 때문입니다.
Gradient를 계산하고 업데이트 하게 되면 line을 넘나들면서 왔다갔다 하게 됩니다.
Loss에 영향을 덜 주는 수평방향 차원의 가중치는 업데이트가 아주 느리게 진행됩니다.
이렇게 빠르게 변하는 수직 차원을 가로지르면서 지그지그로 아주 지저분하게(nasty) 움직이게 됩니다.
아주 바람직하지 않은 행동입니다. 그리고 이 문제는 고차원 공간에서 훨씬 더 빈번하게 발생합니다.
우리가 본 예시 그림은 2차원 밖에 되지 않습니다만 실제로는 가중치가 수천 수억개 일 수 있을 것입니다.
이 경우 수억개의 방향으로 움직일 수 있습니다. 이런 수억개의 방향중에 불균형한 방향이 존재한다면 SGD는 잘 동작하지 않을 것입니다.
수억개의 파라미터가 있다고 했을때 이런 불균형의 발생 비율은 상당히 높습니다.
고차원 공간에서 발생할 수 있는 이런 문제는 실제로도 정말 큰 문제가 됩니다.
SGD에서 발생하는 또 다른 문제는 local minima 와 saddle points와 관련된 문제입니다.
그림을 좀 바꿨습니다. 이제는 X축은 어떤 하나의 가중치를 나타내고 Y축은 Loss를 나타내고 있습니다.
우선 위의 그래프를 보면, 이 휘어진 손실함수는 중간에 "valley"가 하나 있습니다.
이런 상황에서 SGD는 어떻게 움직일까요?
[학생이 대답]
이 경우 SGD는 멈춰버립니다. 왜냐하면 gradient가 0이 되기 때문이죠. locally falt 합니다.
SGD의 동작을 생각해보면 gradient를 계산하고 그 반대방향으로 이동하는 것 이었습니다.
저 위치에서는 "opposite gradient" 도 0 이 되며, 따라서 학습이 멈춰버리게 됩니다.
또 다른 문제는 saddle points에 관한 것입니다.
local minima는 아니지만, 한쪽 방향으로는 증가하고 있고 다른 한쪽 방향으로는 감소하고 있는 지역을 생각해 볼 수 있습니다.
이런 곳에서도 gradient는 0이 됩니다.(아래 그림)
saddle point에서도 gradient = 0 이므로 멈추게 됩니다.
비록 이처럼 1차원의 예제만 봐서는 local minima가 엄청 심각하고 saddle point는 좀 덜 심각해 보이지만,
고차원 공간에서는 그 반대입니다. 여러분에게 1억 차원의 공간이 있다고 생각해 봅시다. 여기에서 saddle point는 무엇일까요?
Saddle point가 의미하는 것이 어떤 방향은 Loss가 증가하고 몇몇 방향은 Loss가 감소하고 있는 곳을 생각해 볼 수 있습니다.
1억개의 차원에서 생각해보면 이는 정말 빈번하게 발생합니다. 사실 거의 모든 곳에서 발생한다고 할 수 있습니다.
Local minima를 생각해보면 1억 개의 방향을 계산했는데 그 방향이 전부 Loss가 상승하는 방향이라는 것입니다.
고차원 공간을 생각하면 그런 일이 발생하는 것은 매우 드문 경우입니다.
지난 몇 년간 알려진 사실은 very large neural network가 local minima 보다는 saddle point에 취약하다는 것입니다.
그리고 또한 saddle point 뿐만 아니라 saddle point의 근처에서도 문제는 발생합니다.
아래 예시를 보면 saddle point 근처에서 gradient가 0 은 아니지만 기울기가 아주 작습니다.
그것이 의미하는 바는 gradient를 계산해서 업데이트를 해도 기울기가 아주 작기 때문에
현재 가중치의 위치가 saddle point 근처라면 업데이트는 아주 느리게 진행됩니다.
이는 아주 큰 문제입니다. 그리고 SGD의 또 다른 문제가 있습니다.
SGD는 Stochastic gradient descent라는 것을 다시한번 명심하시기 바랍니다.
사실 손실함수를 계산할 때는 엄청 엄청 많은 Traing set 각각의 loss를 전부 계산해야 합니다.
이 예시의 N이 전체 training set일 경우에 이 값은 "n = 백만"이 될 수도 있습니다.
Loss를 계산할 때 마다 매번 전부를 계산하는 것은 어렵습니다.
그래서 실제로는 미니배치의 데이터들만 가지고 실제 Loss를 추정하기만 합니다.
이는 매번 정확한 gradient를 얻을 수가 없다는 것을 의미합니다.
대신에 gradient의 부정확한 추정값(noisy estimate) 만을 구할 뿐입니다.
오른쪽에 보이는 것은 제가 좀 과장해서 그린 것입니다.
각 지점의 gradient에 random uniform noise를 추가하고 SGD를 수행하게 만들었습니다.
따라서 실제로 SGD가 이런식으로 동작하진 않지만 이 예제로 gradient에 noise가 들어가면 어떻게 되는지 알 수 있습니다.
손실함수 공간을 이런식으로 비틀거리면서 돌아다니게 되면 minima까지 도달하는데 시간이 더 오래 걸릴 것입니다.
지금까지 SGD에 어떤 문제가 있는지에 대해서 이야기해 보았습니다.
질문 있나요?
[학생이 질문]
질문은 바로 SGD를 쓰지 않고 그냥 GD를 쓰면 이런 문제가 전부 해결되는지 입니다.
자 이전의 taco shell에서의 문제를 다시한번 살펴보면 full batch gradient descent에서도 같은 문제가 발생합니다
Noise의 문제도 한번 볼까요. Noise는 미니배치이기 때문에서만이 아니라 네트워크의 explicit stochasticity 로도 발생합니다.
이는 나중에 더 살펴 볼 것이지만 이는 여전히 문제가 됩니다.
Saddle points 또한 full batch GD에서 문제가 됩니다. 전체 데이터를 사용한다고 해도 여전히 나타날 수 있겠죠
기본적으로 full batch gradient descent를 사용한다 하더라도 이런 문제들이 해결되지는 않습니다.
이러한 위험요소들을 다루기 위해서는 더 좋은 최적화 알고리즘이 필요합니다.
이번 문제들의 대다수를 해결할 수 있는 아주 간단한 방법이 하나 있습니다.
SGD에 momentum term을 추가하는 것이죠
왼쪽은 classic 버전의 SGD입니다. 오로지 gradient 방향으로만 움직이는 녀석이죠
반면 오른쪽은 SGD + momentum 입니다. 엄청 조금의 변화만 있습니다. 2개의 수식과 5라인의 코드를 보실 수 있죠
아이디어는 아주 간단합니다. 그저 velocity를 유지하는 것입니다. gradient 를 계산할 때 velocity를 이용합니다.
현재 미니배치의 gradient 방향만 고려하는 것이 아니라 velocity를 같이 고려하는 것입니다.
여기에는 하이퍼 파라미터 rho가 추가되었습니다. momemtum의 비율을 나타냅니다.
velocity의 영향력을 rho의 비율로 맞춰주는데 보통 0.9와 같은 높은 값으로 맞춰줍니다.
velocity에 일정 비율 rho를 곱해주고 현재 gradient를 더합니다.
이를 통해서 우리는 이제 gradient vector 그대로의 방향이 아닌 velocity vector의 방향으로 나아가게 됩니다.
엄청 간단한 방법이지만 지금까지 말했던 문제들을 해결하는데 많은 도움을 줄 수 있습니다.
local minima와 saddle points문제를 생각해보면 물리적으로 공이 굴러내려오는 것을 상상해 볼 수 있습니다.
이 공은 떨어지면 속도가 점점 빨라집니다.
이 공은 local minima에 도달해도 여전히 velocity를 가지고 있기 때문에 gradient = 0 이라도 움직일 수 있습니다.
때문에 local minima를 극복할 수 있게 되고 계속해서 내려갈 수 있습니다.
saddle points에서도 비슷한 일이 일어나겠죠
saddle point 주변의 gradient가 작더라도, 굴러내려오는 속도가 있기 때문에 velocity를 가지게 됩니다.
때문에 saddle point를 잘 극복해 내고 계속 밑으로 내려올 수 있는 것입니다.
업데이트가 잘 안되는 경우(poor conditioning) 를 다시 한번 살펴보겠습니다.
아래와 같이 지그재그로 움직이는 상황이라면 momentum이 이 변동을 서로 상쇄시켜 버립니다.
이를 통해서 loss에 만감한 수직 방향의 변동은 줄여주고 수평방향의 움직임은 점차 가속화 될 것입니다.
momentum을 추가하게 되면 high condition number problem을 해결하는 데 도움이 되는 것입니다.
오른쪽을 보면 검은색이 일반 SGD입니다. 지그지그로 움직이죠. 파란색이 Momentum SGD입니다.
Momentum을 추가해서 velocity가 생기면 결국 noise가 평균화되버립니다.
보통의 SGD가 구불구불 움직이는 것에 비해서 momemum은 minima를 향해서 더 부드럽게 움직입니다.
질문 있나요?
[학생이 질문]
문제는 어떻게 SGD Momemtum이 poorly conditioned coordinate 문제를 해결할 수 있는지 입니다.
우선 velocity estimation term에서 velocity가 어떻게 계산되는지를 보면 gradient를 계속해서 더해갑니다.
이는 하이퍼파라미터인 rho에 영향을 받습니다. 그리고 현재 gradient가 상대적으로 작은 값이고
그리고 이 상황에서 rho가 적절한 값으로 잘 동작한다고 하면
그러면 velocity가 실제 gradient보다 더 커지는 지점 까지 조금씩 증가할 것입니다.
이는 poorly conditioned dimension에서 더 빨리 학습될 수 있도록 도와줍니다.
SGD momentum를 연상할 때 유용한 그림이 있습니다.
빨간 점이 현재 지점입니다.
Red Vector는 현재 지점에서의 gradient의 방향을 나타냅니다. Green vector는 Velocity vector입니다.
실제 업데이트는(autual step) 이 둘의 가중평균으로 구할 수 있습니다.
이는 gradient의 noise를 극복할 수 있게 해줍니다.
Momentum의 변형이 있습니다. Nesterov accelerated gradient 인데, Nesterov momentum 라고도 합니다.
계산하는 순서를 조금 바꾼 것입니다.
기본 SGD momentum은 "현재 지점" 에서의 gradient를 계산한 뒤에 velocity와 섞어 줍니다.
Nesterov를 사용하면 방법이 조금 다릅니다.
빨간 점에서 시작해서 우선은 Velocity방향으로 움직입니다.
그리고 그 지점에서의 gradient를 계산합니다. 그리고 다시 원점으로 돌아가서 둘을 합치는 것입니다.
완벽한 설명은 아니지만 두 정보를 약간 더 섞어준다고 생각해 볼 수 있을 것입니다.
velocity의 방향이 잘못되었을 경우에 현재 gradient의 방향을 좀 더 활용할 수 있도록 해줍니다.
Nesterov는 Convex optimization 문제에서는 뛰어난 성능을 보이지만
하지만 Neural network와 같은 non-convex problem 에서는 성능이 보장되지는 않습니다.
Nesterov의 수식은 다음과 같습니다.
velocity를 업데이트하기 위해서 이전의 velocity와 (x + pv)에서의 gradient를 계산합니다.
그리고 step update는 앞서 계산한 velocity를 이용해서 구해줍니다.
질문 있나요?
[학생이 질문]
질문은 velocity의 초기값을 구하는 좋은 방법이 있는지 입니다.
velocity의 초기값은 항상 0입니다.
이는 하이퍼파라미터가 아닙니다. 그저 0으로 둡니다.
다른 질문 있나요?
[학생이 질문]
직관적으로 보면 velocity은 이전 gradients의 weighted sum입니다.
[학생이 질문]
그리고 더 최근의 gradients에 가중치가 더 크게 부여됩니다.
매 스텝마다 이전 velocity에 rho(0.9 or 0.99) 를 곱하고 현재 gradient를 더해줍니다.
그리고 이를 moving average라고 볼 수 있습니다. (exponentially weighted moving average)
그리고 시간이 지날수록 이전의 gradient들은 exponentially하게 감소합니다.
Nesterov의 공식을 보시게 되면 다소 까다롭게 생겼습니다. 기존에는 Loss와 Gradient를 같은 점(x_t)에서 구했었습니다.
Nesterov는 이 규칙을 조금 비틀어 버렸습니다. 이는 상당히 성가시지만 다행이도 쉽게 해결할 수 있는 변형 공식이 있습니다.
변수들을 적절히 잘 바꿔주면 Nesterov를 조금 다르게 표현할 수 있으며 Loss와 Gradient를 같은 점에서 계산할 수 있게 됩니다.
그리고 수정된 수식을 통해서 우리는 Nesterov를 새롭게 이해해 볼 수 있습니다.
첫 번째 수식은 기존의 momentum과 동일합니다.
기존과 동일하게 velocity 와 계산한 gradient를 일정 비율로 섞어주는 역할을 합니다.
그리고 두 번째로 맨 밑의 수식을 보시기 바랍니다.
우선 현재 점과 velocity를 더해줍니다. 여기 까지는 기존과 동일하죠
그리고 여기에 "현재 velocity - 이전 velocity" 를 계산해서 일정 비율(rho)을 곱하고 더해줍니다.
Nesterov momentum는 현재/이전의 velocity간의 에러보정(error-correcting term)이 추가됐습니다.
SGD, Momentum, Nesterov의 예시를 한번 살펴봅시다. 기본 SGD은 검정색인데 세월아 네월아 내려가고 있습니다.
파란색과 초록색이 momentum과 Nesterov입니다.
momentum방법들은 minima를 그냥 지나쳐 버리는 경향이 있습니다. 이전의 velocity의 영향을 받기 때문입니다.
하지만 스스로 경로를 수정하고는 결국 minima에 수렴합니다.
질문 있나요?
[학생이 질문]
질문은 이 예시만 보면 momentum이 엄청 좋아 보이는데 만일 minima가 엄청 좁고 깊은 곳이라면 어떻게 되는지 입니다.
momentum의 velocity가 오히려 minima를 건너 뛰는 현상도 발생할 수 있지 않을까요?
그 부분은 상당히 흥미롭습니다. 그리고 이에 관련한 최근의 연구들이 주목하는 주제이기도 합니다.
하지만 사실은 그렇게 좁고 깊은(sharp) minima는 좋은 minima가 아닙니다.
그리고 사실 우리는 그런 곳에 도달하는 것도 원하지 않습니다. 좁고 깊은 minima는 훨씬 더 심한 overfits을 불러오게 됩니다.
가령 Training set을 두배 늘어났다고 생각해보면, 최적화 시키는 산의 지형(landscape)자체가 바뀌게 될 것입니다.
Training data이 더 많이 모이면 그런 민감한 minima는 점점 사라집니다.
여기에서 얻을 수 있는 직관은 우리가 원하는 minima는 아주 평평한 minima 라는 것입니다.
왜냐하면 "아주 평평한 minima"는 Training data의 변화에 좀 더 강인할 지도 모르기 때문입니다.
결국 평평한 minima가 더 일반화를 잘 할 수도 있으며, Testing data에도 더 좋은 결과를 얻을 수 있을 것입니다.
다시한번 말씀드리지만 이는 아주 최근에 연구되고 있는 분야입니다. 아주 좋은 질문을 해 주셨습니다.
그러므로 momentum이 좁고 깊은 minima를 무시해 버리는 것은 버그가 아니라 momentum의 특징이라고 할 수 있습니다.
아직 확실하진 않지만(믿거나 말거나) 이는 momentum의 좋은 점이라고 할 수 있겠습니다.
자 그리고 일반 momentum와 Nesterov이 조금 다르게 움직이는 것을 볼 수 있습니다.
이는 Nesterov에서 추가된 수식 때문입니다. 일반 momentum에 비해서 overshooting이 덜 한 것을 알 수 있습니다.
최적화 방법 중에 AdaGrad도 있습니다.
현재 Stanford에 계시는 John Duchi 교수님께서 Ph.D 시절에 제안하신 방법입니다.
AdaGrad는 훈련도중 계산되는 gradients를 활용하는 방법입니다.
Adagrad는 velocity term 대신에 grad squared term을 이용합니다.
그리고 학습 도중에 계산되는 gradient에 제곱을 해서 계속 더해줍니다.
그리고 Update를 할때 Update term을 앞서 계산한 gradient 제곱 항으로 나눠줍니다.
Condition number인 경우 빨간색 박스 안의 값은 어떨까요?
[학생이 대답]
2차원 좌표가 있다고 해 봅시다. 그 중 한 차원은 항상 gradient가 높은 차원입니다. 그리고 다른 하나는 항상 작은 gradient를 가집니다.
Small dimension에서는 gradient의 제곱 값 합이 작습니다. 이 작은 값이 나눠지므로 가속도가 붙게 됩니다.
Large dimension에서는 gradient가 큰 값 이므로 큰 값이 나눠지게 되겠죠. 그러므로 속도가 점점 줄어듭니다.
하지만 AdaGrad에는 문제가 하나 있습니다. 학습이 계속 진행되면 어떻게 될까요? 학습 횟수 t가 계속 늘어나는 것입니다.
[학생이 대답]
AdaGrad는 step을 진행할수록 값이 점점 작아집니다.
update 동안 gradient의 제곱이 계속해서 더해집니다. 때문에 이 값(estimate)은 서서히(monotonically) 증가하게 됩니다.
이는 Step size를 점점 더 작은 값이 되게 합니다.
손실함수가 convex한 경우에 점점 작아지는 것은 정말 좋은 특징이 될 수 있습니다.
convex case에서는 minimum에 근접하면 서서히 속도를 줄여서 수렴할 수 있게 하면 좋겠죠
Convex case에서는 좋은 특징이라 할 수 있습니다.
하지만 non-convex case에서는 문제가 될 수 있습니다. 가령 saddle point에 걸려버렸을 때 AdaGrad는 멈춰버릴 수 있습니다.
AdaGrad의 변형이 RMSProp입니다. 앞서 언급한 문제를 개선시킨 방법입니다.
RMSProp에서는 AdaGrad의 gradient 제곱 항을 그대로 사용합니다.
하지만 이 값들을 그저 누적만 시키는 것이 아니라 기존의 누적 값에 decay_rate를 곱해줍니다.
이 값은 기존의 momentum 수식과 유사하게 생겼습니다. 다만 gradients의 제곱을 계속해서 누적해 나갑니다.
RMSProp에서는 gradient 제곱 항에 쓰는 decay rate는 보통 0.9 또는 0.99정도를 자주 사용합니다.
그리고 '현재 gradient의 제곱'은 (1 - decay rate) 를 곱해줘서 더해줍니다.
RMSProp은 gradient 제곱을 계속 나눠준다는 점에서 AdaGrad와 유사합니다.
이를 통해 step의 속도를 가속/감속 시킬 수 있습니다.
하지만 RMSProp의 경우에는 위와 같은 특징으로 점점 속도가 줄어드는 문제를 해결할 수 있었습니다.
이 예제에서 SGD는 검정색이고 momentum은 파란색 그리고 RMSProp은 빨간색입니다.
RMSProp이나 momentum은 기본 SGD보다는 훨씬 더 좋습니다. 하지만 이 둘의 행동양상은 조금 다릅니다.
momentum의 경우에는 overshoots한 뒤에 다시 minima로 돌아옵니다.
RMSProp은 각 차원마다의 상황에 맞도록 적절하게 궤적(trajectory)을 수정시킵니다.
여러분들한테는 안보이시겠지만 지금 이 그림에는 초록색으로 AdaGrad도 있습니다. 동일한 Learning rate로 말입니다.
하지만 Learning rates가 점차 감소하기 때문에 RMSProp에 가려서 보이지 않습니다.
실제로 AdaGrad는 잘 쓰이지는 않습니다. 그리고 이런 식의 비교는 사실 AdaGrad에게는 불공정합니다.
아마도 AdaGrad의 Learning rate를 늘리게 되면 RMSProp과 비슷한 동작을 할 것입니다.
하지만 일반적으로 Nerural Network를 학습시킬 때 AdaGrad를 잘 사용하지는 않습니다.
질문 있나요?
[학생이 질문]
이 예시에서의 문제는 convex case입니다. (convex인데 왜 Adagrad에게 불리한지)
하지만 learning rates가 서로 상이하기 때문입니다.
때문에 여러 알고리즘 간에 '같은 Learning rates' 를 가지고 AdaGrad 를 visualization하는 것은 공정하지 못합니다.
visualization을 하고자 한다면 알고리즘 별로 learning rates를 조정하는 것이 좋습니다.
자 우리는 momentum이라는 방법을 알아봤습니다. velocity를 이용해서 step을 조절하는 방법이었습니다.
AdaGrad와 RMSProp은 momentum과 다른 방식을 사용하죠. gradients의 제곱을 나눠주는 방식으로 step을 조절했습니다.
이 둘은(momentum 계열 vs Ada계열) 모두 괜찮은 아이디어인 것 같습니다.
그렇다면 이 두 방법을 조합해보면 어떻까요? 아마 훨씬 더 좋은 방법이 될 것 같습니다.
여기 Adam 이라는 알고리즘이 있습니다. 여기 수식은 Adam과 "유사한" 알고리즘이라고 보시면 됩니다.
앞으로 몇 장의 슬라이드를 통해서 '진짜' Adam 이 되도록 조금씩 바꿔 볼 것입니다.
Adam은 first moment와 second moment을 이용해서 이전의 정보(estimate)를 유지시킵니다.
빨간색 first moment는 gradient의 가중 합입니다.
그리고 second moment는 AdaGrad이나 RMSProp처럼 gradients의 제곱을 이용하는 방법입니다.
Adam으로 Update를 진행하게 되면 우선 first moment는 velocity를 담당합니다.
그리고 sqrt(second moment)를 나눠주는데 second moment는 gradient의 제곱 항입니다.
Adam은 마치 RMSProp + momentum 같아 보입니다. 즉 momentum + second squared gradients 이죠
이 두 종류의 유용한 특징을 모두 이용하는 것입니다. 하지만 여기에도 문제가 하나 있습니다.
초기 step 에서는 어떤 일이 발생할까요? 초기에 second moment를 0으로 초기화합니다.
second moment를 1회 Update 하고 난 후를 생각해봅시다. beta2는 decay_rate로 .9또는 .99로 1에 가까운 값입니다.
그렇기 때문에 1회 업데이트 이후에도 second moment는 여전히 0에 가깝습니다.
update step에서 second moment로 나누게 되는데 나눠주는 값이 크기 때문에 초기 step이 엄청나게 커지게 됩니다.
중요한 것은 이 커진 step이 실제로 손실함수가 가파르기 때문(geometry)이 아니라는 것입니다.
이 값은 second moment을 0으로 초기화 시켰기 때문에 발생하는 '인공적인' 현상입니다.
질문 있나요?
[학생이 질문]
first moment도 second moment처럼 초기에 엄청 작은 값일 것입니다. 따라서
learning rate에 '엄청 작은 값'을 곱하고(first moment) '엄청 작은 값의 제곱근(second)'을 나누면 어떻게 될까요?
어쩌면 서로 상쇄시킬 수 있고. 상쇄됀다면 문제는 해결되는 것이죠.
예 사실입니다. 경우에 따라서 서로 상쇄될 수도 있습니다. 하지만 간혹 엄청 큰 step이 발생하는 경우도 생길 수 있습니다.
하지만 한번 발생하면 정말 나쁜 상황일 것입니다.
가령 여러분이 제대로 초기화를 해주지 않아서 아주 큰 step이 발생했다면
초기화가 엉망이 될 것이고 아주 엉뚱한 곳으로 이동할 수도 있습니다. 결국 수렴할 수 없게 될 수도 있습니다.
질문 있나요?
[학생이 질문]
질문은 수식의 10^-7이 무엇인지 입니다. 저 값은 AdaGrad, RMSProp, Adam에서 등장합니다.
우리는 현재 어떤 값으로 '나눗셈' 를 하고 있습니다. 하지만 그 값이 항상 0이 아니라는 보장은 없죠
따라서 분모에 작은 양수 값을 더해줘서 0이 되는 것을 사전에 방지할 수 있습니다.
이 또한 하이퍼파라미터 이긴 하지만 큰 영향력은 없습니다. 보통 10^-7이나 10^-8정도를 사용하면 잘 동작합니다.
Adam은 초기 Step이 엄청 커져 버릴 수 있고 이로 인해 잘못될 수도 있다고 했습니다.
Adam을 이를 해결하기 위해 보정하는 항을 추가합니다. (bias correction term )
first/second moments를 Update하고 난 후 현재 Step에 맞는 적절한 unbiased term 을 계산해 줍니다.
실제 Adam은 first/second moment만 계산하는 것이 아니라 이렇게 unbiased term을 넣어줘야 합니다.
지금 보시는 부분이 '완전한 Adam' 이라 할 수 있겠습니다.
그리고 Adam은 엄청 좋습니다. 다양한 문제들에도 정말 잘 동작합니다. 저는 어떤 문제에서도 기본 알고리즘으로 Adam을 사용하곤 합니다.
특히나 beta_1 = 0.9, beta_2 = 0.999로 설정하고 Learning rate를 E-3나 E-4 정도로만 설정해 놓으면
거의 모든 아키텍쳐에서 잘 동작하는 기본 설정으로 아주 제격입니다.
일반적으로 Adam으로 시작해 보는 것은 정말 좋습니다.
[웃음]
자 동일한 환경에서 SGD, Momentum, RMSProp, Adam을 한번 비교해 봅시다.
보라색 Adam을 한번 봅시다. momentum과 RMSProp을 짬뽕시켜 놓은듯한 모습입니다.
Adam이 momentum처럼 overshoots하긴 하지만 momentum만큼 엄청 심하지는 않습니다.
그리고 Adam은 RMSProp같은 특징도 가지고 있습니다. 각 차원의 상황을 따로 고려해서 Step을 이동합니다.
여기 단순한 2차원 예제에서 수렴하는 것을 보면 그놈이 그놈같아 보일 수는 있지만
확실한 것은 Adam이 momentum스러우면서도 RMSProp스럽다는 것입니다.
Optimization 알고리즘에 대한 질문 있으신가요?
[학생이 질문]
질문은 Adam이 해결하지 못하는 것은 무엇인지 입니다. Neural networks는 여전이 엄청 크고 학습은 오래걸립니다.
Adam을 쓰더라도 여전히 문제점들이 있습니다.
가령 손실함수가 타원형일 경우를 생각해 봅시다.
Adam을 이용하면 각 차원마다 적절하게 속도를 높히고 줄이면서 '독립적으로' step을 조절할 것입니다.
하지만 이 타원이 축 방향으로 정렬되어 있지 않고 기울어져 있다고 생각해 봅시다.
이 경우에도 Adam은 차원에 해당하는 축 만을 조절할 수 있습니다.
이는 차원을 회전시킨 다음에 수평/수직 축으로만 늘렸다 줄였다 하는 것입니다. 회전을 시킬수는 없죠
이러한 회전된 타원(poor conditioning) 문제는 Adam을 비롯한 다른 여러 알고리즘들도 다룰 수 없는 문제입니다.
지금까지의 모든 Opimization 알고리즘은 learning rate 이라는 하이퍼파라미터를 가지고 있었습니다.
지난 시간이 이 그림을 본 적 있을 것입니다.
Learning rate가 지나치게 높으면 노란색 처럼 솟구치게 되겠죠
파란색 처럼 너무 낮으면 수렴하는데 너무 오래걸립니다.
하지만 learning rate를 잘 고르는 것은 상당히 까다롭습니다.
우리는 학습 과정에서 learning rate 하나를 정해놓고 시작해야 하기 때문에 잘 고르는게 참 어렵습니다.
learning rates dacay 전략을 사용해 볼 수 있습니다. 각각의 learning rates의 특성을 적절히 이용하는 것이죠
처음에는 learning rates를 높게 설정한 다음에 학습이 진행될수록 learning rates를 점점 낮추는 것입니다.
다양한 전략을 시도해 볼 수 있지만 가령 100,000 iter에서 learning rates를 낮추고 학습시키는 것입니다.(step decay)
혹은 exponential decay 처럼 학습과정 동안에 꾸준히 learning rate를 낮출 수도 있습니다.
꾸준히 learning rate를 감소시키는 것에는 다양한 전략이 있을 수 있습니다.
오른쪽의 그림을 보시기 바랍니다. Resnet 논문에 있는 그림입니다. Loss가 계속 내려가고 있습니다.
그리고 어느순간 평평해 지는 듯 하더니 다시 또 내려가는 것을 반복하는 것을 알 수 있습니다.
Resnet 논문에서는 step decay learning rate 전략을 사용한 것입니다.
평평해지다가 갑자기 내려가는 구간은 Learning rate를 낮추는 구간입니다.
learning rate를 언제 낮춰야 하는지를 생각해보면, 현재 수렴을 잘 하고 있는 상황에서 gradient가 점점 작아지고 있는 것입니다.
learning rate가 너무 높아서 더 깊게 들어가지 못합니다. (bouncing around too much)
이 상황에서 learning rate를 낮추게 되면 속도가 줄어들 것이고 지속해서 Loss를 내려갈 수 있을 것입니다.
실제로 상당히 도움이 되는 방법입니다.
그리고 한가지 말씀드릴 것은 learning rate decay는 Adam 보다는 SGD Momentum을 사용할 때 자주 씁니다.
또 한가지 말씀드릴 것은 learning rate decay는 부차적인 (second-order ) 하이퍼파라미터 라는 것입니다.
일반적으로 learning-rate decay를 학습 초기부터 고려하지는 않습니다.
보통 학습 초기에는 learning rate decay가 없다고 생각하고 learning rate를 잘 선택하는 것이 중요합니다.
learning rate와 dacay 등을 cross-validate 하려고 한다면 문제가 너무 복잡해 집니다.
learning rate decay를 설정하는 순서는 우선 decay 없이 학습을 시켜 봅니다.
그리고 Loss curve를 잘 살피고 있다가 decay가 필요한 곳이 어디인지 고려해 보는 것이 좋습니다.
지금까지 배운 Optimization 알고리즘들을 모두 1차미분을 활용한(first-order) 방법이었습니다.
그림처럼 1차원의 손실함수가 있다고 생각해 봅시다. 우리는 지금 빨간색 점에 있는 것입니다.
이 점에서 gradient 를 계산하겠죠
이 gradient 정보를 이용해서 우리는 손실함수를 선형함수로 근사시킵니다.
이는 일종의 1차 테일러 근사입니다. (first-order Taylor apporximation)
우리는 이 1차 근사함수를 실제 손실함수라고 가정하고 Step을 내려갈 것입니다.
하지만 이 근사함수로는 멀리갈 수 없습니다.
현재 우리가 사용하는 정보는 1차 미분값일 뿐입니다. 그리고 우리는 조금 더 괜찮은 방법을 생각해 볼 수도 있을 것입니다.
2차 근사 (second-order approximation)의 정보를 추가적으로 활용하는 방법이 있습니다.
이는 2차 테일러 근사 함수가 될 것이고 이 함수는 2차함수의 모양입니다.
2차 근사를 이용하면 minima에 더 잘 근접할 수 있습니다. you're really happy
이것이 바로 2nd-order optimization의 기본 아이디어입니다.
방금 예시는 다차원으로 확장시켜보면 이를 'Newton step' 이라고 합니다.
Hessian matrix를 계산합니다. 2차 미분값들로 된 행렬입니다.
Hessian matrix의 역행렬을 이용하게 되면 실제 손실함수의 2차 근사를 이용해 minima로 곧장 이동할 수 있을 것입니다.
혹시 이 알고리즘이 다른 Optimization 알고리즘에 비해 특이한 것이 무엇인지 아시겠습니까?
[학생이 대답]
네 맞습니다. Learning rate가 없습니다. That's kind of cool.
지금 우리는 2차근사 함수를 만들었고 이 2차근사 함수의 minima로 이동하는 것입니다.
적어도 "기본적인 Newton's method" 에서는 learning rate는 불필요합니다.
매 step마다 항상 minma를 향해 이동합니다.
하지만 실제로는 learning rate가 필요합니다. 왜냐하면 2차 근사도 사실상 완벽하지 않기 때문이죠
minima로 이동하는게 아니라 'minima의 방향'으로 이동하기 때문이죠 어쨌든 기본버전에는 learning rate가 없습니다.
하지만 불행하게도 Deep learning에서는 사용할 수 없습니다.
왜냐하면 Hessian matrix는 N x N 행렬입니다. N은 Network의 파라미터 수입니다.
N이 1억이면 1억의 제곱만큼 존재할 것입니다.
이를 메모리에 저장할 방법은 없으며 또한 역행렬계산도 불가능 할 것입니다.
그래서 실제로는 'quasi-Newton methods' 를 이용합니다.
Full Hessian을 그대로 사용하기 보다 근사시킵니다. Low-rank approximations 하는 방법입니다.
여러분도 앞으로 간혹 접하게 될 것입니다.
L-BFGS도 second-order optimizer입니다. 이 방법도 Hassian을 근사시켜서 사용하는 방법입니다.
L-BFGS도 여러분이 가끔씩 보게될텐데 사실상 DNN에서는 잘 사용하지 않습니다.
왜냐하면 L-BFGS에서 2차근사가 stochastic case에서 잘 동작하지는 않기 때문입니다.
그리고 L-BFGS는 non-convex problems에도 적합하지 않습니다.
더 깊게는 들어가지 않겠습니다.
실제로는 Adam을 제일 많이 씁니다.
하지만 full batch update가 가능하고 stochasticity이 적은 경우라면 L-BFGS가 좋은 선택이 될 수 있습니다.
L-BFGS가 Neural network를 학습시키는데 그렇게 많이 사용되지는 않지만
앞으로 보게될 Sytle tranfer와 같은 알고리즘에 L-BFGS을 종종 사용할 수 있습니다.
Sytle tranfer같은 stochasticity와 파라미터가 적은 경우에서 Optimization을 해야할 경우에 말이죠
지금까지 이야기했던 모든 것들을 전부 training error를 줄이기 위한 방법들이었습니다.
optimization 알고리즘들은 training error를 줄이고 손실함수를 최소화시키기 위한 역할을 수행합니다.
하지만 사실 우리는 Training error에 크게 신경쓰지 않습니다.
대신에 "한번도 보지 못한 데이터"에 대한 성능이 더 중요하죠
우리가 원하는 것은 train/test error의 격차를 줄이는 것입니다.
질문은 바로 우리가 손실함수 최적화를 이미 모두 끝마친 상황에서
'한번도 보지 못한 데이터' 에서의 성능을 올리기 위해서는 어떻게 해야 할까요?
가장 빠르고 쉬운 길은 바로 모델 앙상블입니다.
Machine learning 분야에서 종종 사용하는 기법입니다.
아이디어는 아주 간단합니다. 모델을 하나만 학습시키지 말고 10개의 모델을 독립적으로 학습시키는 것입니다.
결과는 10개 모델 결과의 평균을 이용합니다.
모델의 수가 늘어날수록 overfitting 줄어들고 성능이 조금씩 향상됩니다. 보통 2%정도 증가하죠
엄청나게 큰 변화는 아니지만 상당히 일관적으로 이 정도 늘어납니다.
Imagenet 같은 대회에서는 모델의 성능을 최대화 시키기 위해서 이러한 앙상블 기법을 사용하는 모습을 볼 수 있습니다.
조금 더 창의적인 방법도 있습니다. 모델을 독립적으로 학습시키는 것이 아니라
학습 도중 중간 모델들을 저장(sanpshots)하고 앙상블로 사용할 수 있습니다.
그리고 Test time에는 여러 snapshots에서 나온 예측값들을 평균을 내서 사용합니다.
이런 snapshots은 Training 과정 중간에 저장하는 것입니다.
이번주에 ICLR에 좀 더 향상된 앙상블 알고리즘이 발표되었습니다. 이 방법은 아주 독특한 Learning rate 스케줄을 이용합니다.
Learning rate를 엄청 낮췄다가 다시 엄청 높혔다가를 반복합니다.
이 논문의 아이디어는 이런 방식으로 손실함수에 다양한 지역에 수렴할 수 있도록 만들어 줍니다.
이런 앙상블 기법으로 모델을 한번만 Train시켜도 좋은 성능을 얻을 수 있게 하는 방법입니다.
질문있나요?
질문은 모델간의 Loss 차이가 크면 한쪽이 overfiting 일 수 있으니 별로 안좋고, 또 차이가 작아도 안좋지 않냐는 것입니다.
그러니 좋은 앙상블 결과를 위해서라면 모델 간의 최적의 갭을 찾는 것이 중요하지 않느냐는 것입니다.
사실 갭이 중요한 것이 아닙니다.
중요한 것은 validation set의 성능을 최대화시키는 것입니다.
하지만 우선 갭을 신경쓰지 않고 모델을 조금 더 Overfitting 시킬 수 있다면 아마 더 좋은 성능을 낼 수 있을 것입니다.
Validation set 성능과 이 갭 사이에는 묘한 관계가 있긴 하지만 오로지 Validation set 성능만 신경쓰면 됩니다.
질문있나요?
[학생이 질문]
질문은 앙상블 모델마다 하이퍼파라미터를 동일하게 줘야 하는지 입니다.
좋은 질문이군요. 그렇지 않을 수도 있습니다.
다양한 "모델 사이즈", "learning rate", 그리고 "다양한 regularization 기법" 등을 앙상블 할 수 있습니다.
실제로 그렇게 사용하기도 합니다.
또 다른 방법으로는 학습하는 동안에 파라미터의 exponentially decaying average를 계속 계산합니다.
이 방법은 학습중인 네트워크의 smooth ensemble 효과를 얻을 수 있습니다.
checkpoints에서의 파라미터를 그대로 쓰지 않고 smoothly decaying average를 사용하는 방법입니다.
이를 Polyak averaging라고 합니다. 때때로 조금의 성능향상을 보일 수 있습니다.
이 또한 시도해볼만한 방법이긴 하지만 실제로 자주 사용하지는 않습니다.
그렇다면 앙상블이 아닌 단일 모델의 성능을 향상시키기 위해서는 어떻게 해야 할까요?
앙상블을 하려 한다면 test time에 10개의 모델을 돌려야 할 수도 있습니다. 그렇게 좋은 방법은 아니죠
단일 모델의 성능을 올리는 것이 우리가 정말 원하는 것입니다.
바로 regularization입니다.
우리가 모델에 어떤 것을 추가할 텐데 모델이 training data에 fit하는 것을 막아줄 것입니다.
그리고 한번도 보지 못한 데이터에서의 성능을 향상시키는 방법입니다.
우리는 이미 몇 가지 regularization 기법을 살펴봤습니다. Loss에 추가적인 항을 삽입하는 방법이었습니다.
손실함수에서 기존의 항은 training data에 fit하려 하고 다른 하나는 regularization term 이죠
과제에서도 있었죠 L2 regularization이 대표적인 예입니다.
앞서 강의에서도 말씀드렸듯이 L2 regularization은 Neural networks에는 잘 어울리지 않습니다.
때문에 조금 다른 것을 사용하죠
Neural network에서 가장 많이 사용하는 regularization은 바로 dropout입니다.
Dropout은 정말 간단합니다.
forward pass 과정에서 임의로 일부 뉴런을 0으로 만드는 것입니다.
forward pass 할때마다 0이 되는 뉴런이 바뀝니다. Dropout은 한 레이어씩 진행하게 됩니다.
한 레이어의 출력을 전부 구합니다. 그리고 임의로 일부를 0으로 만듭니다. 그리고 다음 레이어로 넘어가는 식입니다.
왼쪽에는 dropout이 없고 오른쪽은 dropout이 적용된 경우 입니다.
오른쪽 모델은 동일한 네트워크의 더 작아진 버전 처럼 생겼습니다. 오로지 뉴런의 일부만 사용하고 있습니다.
forward pass iteration 마다 그 모양은 계속 바뀝니다.
질문 있나요?
[학생이 질문]
질문은 지금 무엇을 0으로 놓는 것인지 입니다. activations을 0으로 설정하는 것입니다.
각 레이어에서 next activ= prev activ * weight 죠
현재 activations의 일부를 0으로 만들면 다음 레이어의 일부는 0과 곱해질 것입니다.
질문 있나요?
[학생이 질문]
질문은 어떤 종류의 레이어에서 이를 사용하는지 입니다.
Dropout은 fc layer에서 흔히 사용합니다. 하지만 conv layers에서도 종종 볼 수 있습니다.
Conv net의 경우에서는 전체 feature map에서 dropout을 시행합니다.
conv layer의 경우에 여러 channels이 있기 때문에 일부 channel 자체를 dropout 시킬 수도 있겠습니다.
실제로 Dropout 구현은 아주 쉽습니다. 두 줄이면 충분합니다.
여기 3-layer neural network 예제가 있습니다. 여기에 Dropout을 추가했습니다.
임의로 0으로 설정하는 부분만 추가하면 됩니다. 구현하기 아주 쉽습니다.
그렇다면 dropout이 도대체 왜 좋을까요?
일부 값들을 0으로 만들면서 training time의 네트워크를 심각하게 훼손시키고 있습니다.
이런 일이 어떻게 가능할까요?
대략적으로 말씀드리면, 특징들 간의 상호작용(co-adaptation)을 방지한다고 볼 수 있습니다.
자 우선 우리에게 고양이를 분류하는 어떤 네트워크가 있다고 해봅시다.
어떤 뉴런은 눈에대해, 어떤 뉴런은 꼬리에대해, 또 어떤 뉴런은 고양이의 털에 대해 학습하는 것을 상상해 볼 수 있을 것입니다.
그리고 이 이미지가 고양이인지 아닌지를 이 정보들을 모두 취합해서 결정을 내리는 것입니다.
Dropout을 적용하게 되면 네트워크가 어떤 일부 features에만 의존하지 못하게 해줍니다.
대신에 모델이 "고양이다" 라고 예측할 때 다양한 features를 골고루 이용할 수 있도록 합니다.
따라서 Dropout이 Overfitting을 어느정도 막아준다고 할 수 있겠습니다.
그리고 최근 Dropout에 대한 새로운 해석이 나왔는데 단일 모델로 앙상블 효과를 가질 수 있다는 것입니다.
자 여기 왼쪽의 Dropout을 적용한 네트워크를 살펴보면 뉴런의 일부만 사용하는 서브네트워크라는 것을 알 수 있습니다.
Dropout으로 만들 수 있는 서브네트워크의 경우의 수가 정말 다양하다는 것을 알 수 있습니다.
따라서 Dropout은 서로 파라미터를 공유하는 서브네트워크 앙상블을 동시에 학습시키는 것이라고 생각할 수 있습니다.
하지만 뉴런의 수에 따라서 앙상블 가능한 서브네트워크의 수가 기하급수적으로 증가하기 때문에
가능한 모든 서브네트워크를 사용하는것은 사실상 불가능합니다.
Dropout은 아주 거대한 앙상블 모델을 동시에 학습 시키는 것이라고 볼 수 있겠습니다.
그렇다면 Dropout을 사용하면 Test time에 어떤 일이 일어날까요?
Dropout을 사용하게되면 기본적으로 Neural network의 동작 자체가 변하게 됩니다.
기존의 Neural network는 가중치 w와 입력 x에 대한 함수(f) 였습니다.
하지만 Dropout을 사용하면 Network에 z라는 입력이 추가됩니다. z는 "random dropout mask" 입니다.
z는 random입니다. 하지만 test time에 임의의 값을 부여하는 것은 좋지 않습니다.
가령 여러분이 Facebook에서 일하고 있고 사람들이 업로드하는 이미지를 분류하려 한다고 해봅시다.
오늘은 고양이라고 분류했던 이미지를 내일이 되서는 다른 이미지라고 분류한다고 하면 그닥 좋지 않은 상황이겠죠
따라서 네트워크가 이미 학습된 네트워크의 Test time에는 이러한 임의성(stochasticity)은 적절하지 않습니다.
대신 그 임의성(randomness)을 average out 시킵니다.
이는 적분을 통해 randomness를 marginalize out시키는 것으로 한번 생각해 볼 수 있을 것입니다. 하지만 실제로는-
이 적분을 다루기는 상당히 까다롭습니다.
이 문제를 해결할 수 있는 간단한 방법 중 하나는 샘플링을 통해서 적분을 근사시키는 것인데요
z를 여러번 샘플링해서 test time에 이를 average out 시키는 것입니다.
하지만 이 방법도 Test time에서의 randomness을 만들어 내기 때문에 좋지 않은 방법입니다.
고맙게도 dropout의 경우에는 일종의 locally cheap한 방법을 이용해서 이 적분식을 근사화시킬 수 있습니다.
가령 여기 하나의 뉴런이 있습니다. 출력은 a 이고 입력 x, y가 있고 가중치 w_1, w_2가 있습니다.
Test time에서 a는 w_1x + w_2y 입니다.
자 그럼 이 네트워크를 dropout(p = 0.5) 를 적용해서 train 시킨다고 생각해 봅시다.
train time에서의 기댓값은 아래와 같은 경우로 (analytically) 계산해 볼 수 있습니다.
dropout mask에는 4가지 경우의 수가 존재합니다. 이제 그 값들을 4개의 마스크에 대해 평균화 시켜 줍니다.
Train time에서 a의 기댓값은 1/2(w_1x + w_2y) 입니다.
이 부분에서 test/train time 간의 기댓값이 서로 상이합니다. train time의 기댓값은 test time의 절반밖에 안되죠
Test time에서 stochasticity를 사용하지 않고 할 수 있는 값 싼(cheap) 방법 중 하나는
대신에 dropout probability를 네트워크의 출력에 곱합니다. 자 이제 둘의 기댓값이 같아졌습니다.
이 방법은 이전의 복잡한 적분식을 아주 저렴하게(cheap) local approximation시킬 수 있는 방법입니다.
실제로 많은 사람들이 Dropout을 사용할 때 이 방법을 많이 사용합니다.
Dropout을 사용하게 되면 네트워크 출력에 dropout probability를 곱해줘야 합니다.
Dropout에 대해 요약해보자면 Forward pass에 Dropout 을 추가시키는 것은 상당히 간단합니다.
일부 노드를 무작위로 0으로 만들어주는데는 2줄이면 충분하죠
그리고 Test time에서는 그저 값 하나만 곱해주면 됩니다. (probability)
Dropout은 상당히 간단합니다. 그리고 Neural network의 Regularization에 상당히 효과적이죠
그리고 Dropout을 사용할 때 한가지 트릭을 생각해 볼 수 있습니다. Dropout을 역으로 계산하는 것입니다 (inverted dropout)
Test time에는 곱하기 연산이 하나 추가되는 것은 상당히 신경쓰이는 일입니다. Test time에서는 계산효율이 중요합니다
Test time에는 기존의 연산을 그대로 사용하고 대신 Train time 에서 p를 나눠줍니다. 보통 train은 GPU로 하기 때문이죠
Train time에서는 곱하기 몇 번 추가되는 것에 별로 신경쓰지 않지만 Test time에서는 가능한 효율적으로 동작하길 원합니다.
질문 있나요?
[학생이 질문]
질문은 dropout을 사용하게 되면 Train time에서 gradient에는 어떤 일이 일어나는지 입니다.
Dropout이 0으로 만들지 않은 노드에서만 Backprop이 발생하게 됩니다.
때문에 dropout을 사용하게 되면 전체 학습시간이 늘어납니다. 각 스텝마다 업데이드되는 파라미터의 수가 줄어들기 때문이죠
다시 말해 Dropout을 사용하게 되면 전체 학습시간은 늘어나지만 모델이 수렴한 후에는 더 좋은 일반화 능력을 얻을 수 있습니다.
사실 Dropout은 여기 보이는 일반적인 regularization 전략을 구체화시킨 하나의 예시에 불과합니다. 이 전략은 -
Train time에는 네트워크에 무작위성(randomness)을 추가해 training data에 너무 fit하지 않게 합니다.
네트워크를 마구잡이로 흩뜨려 놓으므로써 training data에 fit하는 것을 방해하는 것입니다.
그리고 Test time에서는 randomness을 평균화 시켜서 generalization 효과를 주는 것입니다.
Dropout이 Regularization에 가장 대표적인 예이긴 하지만 Batch normalization 또한 이와 비슷한 동작을 할 수 있습니다.
Train time의 BN를 상기해보면 mini batch로 하나의 데이터가 샘플링 될 때 매번 서로 다른 데이터들과 만나게 됩니다.
Train time에서는 각 데이터에 대해서 이 데이터를 얼마나 어떻게 정규화시킬 것인지에 대한 stochasticity이 존재했습니다.
하지만 test time에서는 정규화를 mini batch 단위가 아닌 global 단위로 수행함으로써 stochasticity를 평균화 시킵니다.
이런 특성 때문에 BN 은 Dropout과 유사한 Regularization 효과를 얻을 수 있었습니다.
Train time에는 stochasticity(noise)가 추가되지만 Test time에서는 전부 평균화 되기 때문입니다.
실제로 BN을 사용할 때는 Dropout을 사용하지 않습니다. BN에도 충분히 regularization 효과가 있기 때문이죠
하지만 여전히 Dropout은 쓸모 있습니다. 우리가 자유롭게 조절할 수 있는 파라미터 p가 있기 때문이죠. BN에는 없는 것이죠
이러한 Regularization 패러다임에 부합하는 또 한가지 전략은 바로 data augmentation 입니다.
기본 버전의 학습과정에서는 데이터가 있고 레이블이 있고 이를 통해 매 스텝 CNN을 업데이트했습니다.
하지만 그 대신 train time에 이미지를 무작위로 변환시켜 볼 수 있겠습니다. 레이블은 그대로 놔둔 채로 말입니다.
이제 우리는 원본 이미지를 사용하는 것이 아니라 무작위로 변환시킨 이미지로 학습시키게 되는 것입니다.
가령 이미지가 horizontal flips 할 수 있겠습니다. 이미지가 반전되도 고양이는 여전히 고양이죠
혹은 이미지를 임의의 다양한 사이즈로 잘라서(crop) 사용할 수도 있습니다. 그래도 여전히 이미지는 고양이죠
자 그럼 test time에서 stochasticity를 average out 시키는 것을 한번 생각해봅시다.
"네개의 각 코너" 와 "중앙" 에서 잘라낸 이미지와 이들의 "반전 이미지"를 사용합니다.
ImageNet 관련 모델들의 논문을 읽어보면 저자들이 보통 하나의 이미지를 그대로 사용했을 때의 성능과
이미지 한장에서 10개를 잘라내서의 성능을 비교하곤 합니다. *10개 = (4개코너 + 중앙) x (그냥 + 반전)
Data augmentation으로 color jittering도 있습니다. 학습 시 이미지의 contrast 또는 brightness를 바꿔줍니다.
color jittering에는 조금 더 복잡한 방법도 있습니다. PCA의 방향을 고려하여 color offset을 조절하는 방법입니다.
이 방법은 color jittering을 좀 더 data-dependent한 방법으로 진행하는 것입니다. 자주 사용하는 방법은 아닙니다.
일반적으로 data augmentation는 어떤 문제에도 적용해 볼 수 있는 아주 "일반적인 방법" 이라고 할 수 있습니다.
어떤 문제를 풀려고 할 때, 이미지의 label을 바꾸지 않으면서 이미지를 변환시킬 수 있는 많은 방법들을 생각해 볼 수 있습니다.
Train time에 입력 데이터에 임의의 변환을 시켜주게 되면 일종의 regularization 효과를 얻을 수 있습니다.
그 이유를 다시 말씀드리면 train time에는 stochasticity가 추가되고 test time에는 marginalize out 되기 때문이죠
지금까지 세 가지의 예시를 살펴보았습니다. dropout, batch normalization, data augmentation 이죠
하지만 또 다른 많은 방법들이 존재합니다.
여러분들도 Regularization의 패턴을 잘 숙지하고 논문을 읽다보면 그런 방법들이 눈에 잘 들어올 것입니다.
Dropout과 유사한 방법이 하나 더 있습니다. DropConnect라는 방법이죠
DropConnect은 activation이 아닌 weight matrix를 임의적으로 0으로 만들어주는 방법입니다.
Dropout과 동작도 아주 비슷합니다.
그리고 또 한가지 방법이 있습니다. 사람들이 자주 쓰지는 않지만 개인적으로 아주 좋은 아이디어라고 생각합니다.
fractional max pooling 이라는 방법입니다.
보통 2x2 maxpooling 연산은 고정된 2x2 지역에서 수행합니다. 하지만 fractional max pooling에서는 그렇게 하지 않고
pooling연산을 수행 할 지역이 임의로 선정됩니다.
여기 오른쪽 예시를 보시면 Train time에 샘플링될 수 있는 임의의 pooling region을 보실 수 있습니다.
그리고 test time에 stochasticity를 average out 시키려면
pooling regions를 고정시켜 버리거나 혹은 여러개의 pooling regions을 만들고 averaging over시킵니다.
많이 사용하는 방법은 아니지만 참 좋은 아이디어입니다.
Regularization pattern이라는 패러다임에서 봤을때 아주 놀랄만한 논문이 작년(2016)에 나왔습니다.
올해 강의에 새롭게 소개시켜 드리는 논문입니다. stochastic depth에 관련한 논문이죠
왼쪽의 네트워크를 한번 보시죠 우리에게 아주 깊은 네트워크가 있다고 해봅시다.
train time에 네크워크의 레이어를 randomly drop합니다.
Train time에는 layer 중 일부를 제거해 버리고 일부만 사용해서 학습합니다.
그리고 test time에는 전체 네트워크를 다 사용합니다.
정말 놀라운 연구가 아닐 수 없습니다.
하지만 이 방법의 regularization 효과는 dropout과 같은 다른 방법들과 유사합니다.
그렇지만 아주 놀랍고 아주 최신의 연구이며(cutting-edge) 실제로 잘 사용하진 않지만 아주 좋은 아이디어입니다.
regularization에 대해서 질문 있으신가요?
[학생이 질문]
질문은 보통 하나 이상의 regularization 방법을 사용하는지 입니다.
일반적으로는 batch normalization를 많이 사용합니다. 대부분의 네트워크에서 보통 잘 동작하기 때문이죠
아주 깊은 네트워크에서도 수렴을 잘 하도록 도와줍니다.
대게는 BN만으로 충분합니다만 overfitting이 발생한다 싶으면 Dropout과 같은 다양한 방법을 추가해 볼 수 있습니다.
보통은 이를 가지고 blind cross-validation 를 수행하지는 않습니다.
대신에 네트워크에 overfit의 조짐이 보일때 하나씩 추가시켜 보는 것입니다.
모델을 빠르게 학습시킬 수 있는 방법 중에는 transfer learning이 있습니다.
지금까지는 regularization를 배웠습니다. 다양한 전략으로 train/test error간의 격차를 줄여보려는 것이었죠
overfitting이 일어날 수 있는 상황중 하나는 바로 충분한 데이터가 없을 때 입니다.
우리는 엄청 크고 파워풀한 모델을 원할지 모르겠지만 그 모델은 아주 작은 데이터셋을 지나치게 overfit할 수 있습니다.
Regularization이 이를 해결할 수 있는 전략 중 하나입니다만 Transfer learning 이라는 방법도 있습니다.
Transfer learning은 "CNN 학습에는 엄청많은 데이터가 필요함" 이라는 미신을 무너뜨려버립니다.
아이디어는 정말 간단합니다.
우선 여기 CNN모델이 있다고 해봅시다. VGG스럽게 생긴 모델입니다.
이 CNN을 가지고 우선은 ImageNet과 같은 아주 큰 데이터셋으로 학습을 한번 시킵니다.
이정도 데이터셋이면 전체 네트워크를 학습시키기에 충분한 양입니다.
자 이제 할 일은 Imagenet에서 학습된 features를 우리가 가진 작은 데이터셋에 적용하는 것입니다.
이제는 1000개의 ImageNet 카테고리를 분류하는 것이 아니라 10종의 강아지를 분류하는 문제입니다. 데이터는 엄청 적습니다.
이 작은 데이터셋은 C개의 클래스만 가지고있습니다.(10개)
일반적인 절차는, 우선 가장 마지막의 FC Layer는 최종 feature와 class scores간의 연결인데 이를 초기화시킵니다.
기존에 ImageNet을 학습시킬 때는 4,096 x 1,000 차원의 행렬이었습니다.
하지만 우리의 새로운 문제를 풀기 위해서 4,096 x 10(C)으로 바꿔주게 됩니다.
그리고 방금 정의한 가중치 행렬은 초기화시킵니다. 그다음 나머지 이전의 모든 레이어들의 가중치는 freeze시킵니다.
그렇게 되면 linear classifier를 학습시키는 것과 같습니다. 오로지 마지막 레이어만 가지고 우리 데이터를 학습시키는 것입니다.
이 방법은 사용하면 아주 작은 데이터셋일지라도 아주 작 동작하는 모델을 만들 수 있습니다.
만일 데이터가 조금 더 있다면 전체 네트워크를 fine-tuning 할 수 있습니다.
최종 레이어들을 학습시키고 나면, 네트워크의 일부만이 아닌 네트워크 전체의 학습을 고려해 볼 수도 있을 것입니다.
데이터가 더 많이 있다면 네트워크의 더 많은 부분을 업데이트 시킬 수 있을지도 모릅니다.
이 부분에서는 보통 기존의 Learning rate보다는 낮춰서 학습시킵니다.
왜냐하면 기존의 가중치들이 이미 ImageNet으로 잘 학습되어 있고 이 가중치들이 대게는 아주 잘 동작하기 때문입니다.
우리가 가진 데이터셋에서의 성능을 높히기 위해서라면 그 가중치들을 아주 조금씩만 수정하면 될 것입니다.
따라서 transfer learning을 수행 함에 있어서 이렇게 생긴 2 x 2의 격자 시나리오를 예상해 볼 수 있을 것입니다.
우선 아주 적은 양의 데이터셋이 있는 경우와 아주 많은 양의 데이터셋이 있는 경우가 있겠죠
그리고 이전에 학습된 데이터셋과 현재 데이터셋이 얼마나 유사한지의 경우도 생각해 볼 수 있습니다.
기존의 데이터와 유사한 경우라면 아주 순조로운 출발입니다.
가령 현재의 데이터셋이 ImageNet와 유사하지만 소량의 경우라면, 기존 모델의 마지막 레이어만 학습시켜 볼 수 있겠습니다
데이터가 그보다는 조금 많다고 생각이 되면 모델 전체를 fine tuning해 볼 수도 있을 것입니다.
하지만 ImageNet과 다소 다르게 생긴 데이터셋을 가지고있다면 문제가 될 수 있습니다.
가령 X-rays나 CAT scans와 같은 의료영상들은 대게 ImageNet의 데이터와는 많이 다릅니다.
이 경우에는 좀 더 창의적인 방법이 필요할 수 있습니다.
기존의 전략이 잘 동작할 수도 있겠지만 어쩌면 최종 레이어만 학습시키는 전략이 쓸모없어 질 수도 있을 것입니다.
어쩌면 네트워크의 더 많은 부분은 다시 초기화시켜야 하거나 하는 더 창의적이고 경험적인 부분이 필요합니다.
다만 이 문제는 여러분의 데이터셋이 아주 크다면 조금 완화됩니다. 이 경우에는 더 많은 레이어를 fine-tune 해 볼수 있기 때문이죠
한가지 말씀드리고 싶은 것은 transfer learning이 아주 보편적이라는 것입니다.
사실 transfer learning은 거의 일상적인 수준이 되었습니다.
Computer vision 관련 논문들을 읽어보면 다양한 task에 대한 다음과 같은 시스템 다이어그램을 보실 수 있을 것입니다.
왼쪽은 Object Detection과 관련된 다이어그램입니다. 오른쪽은 Image Captioning과 관련된 것이죠
두 모델 모두 CNN구조를 가지고 있고 기본적으로 이미지를 처리합니다.
요즘에는 거의 모든 computer vision 관련 응용 알고리즘들이 모델들을 밑바닥부터(from scrtch) 학습시키지 않습니다.
대부분은 ImageNet pretrained-model을 사용하고 현재 본인의 task에 맞도록 fine tune 합니다.
captioning의 경우 word vectors를 pretrain하기도 합니다.
pretrained CNN 뿐만 아니라 규모가 큰 말뭉치로부터 학습된 pretrained word vectors도 함께 이용할 수 있겠습니다.
captioning task에서는 pretrained word vectors을 사용하는 경우가 그닥 많지 않고 크게 중요하지 않습니다.
여러분에게 어떤 문제가 있는데 이 문제에 대한 데이터셋이 크지 않은 경우라면
우선 여러분의 task와 유사한 데이터셋으로 학습된 pretrained model 다운로드 받습니다.
그리고 이 모델의 일부를 초기화시키고 여러분 데이터로 모델을 fine-tune 합니다.
여러분의 Training data가 적당히만 있다면 아마 아주 잘 동작할 것입니다.
이런 경우가 너무 흔하기 때문에 대부분의 딥러닝 소프트웨어 패키지들은 model zoo를 제공합니다.
단지 접속만 하면 다양한 모델들의 pretrained 버전을 손쉽게 다운로드 받을 수 있습니다.
오늘 한 내용을 요약해 보자면 우선 optimization을 배웠습니다. training loss를 개선하는 방법이었죠.
regularization에 대해서도 배웠습니다. test data에서의 성능을 향상시키는 방법이었습니다.
Model ensembling도 regularization에 속했었죠
그리고 transfer learning에 대해서도 배웠습니다. 데이터가 적을때 할 수 있는 아주 좋은 방법이었습니다.
이들은 모두 아주 좋은 방법들입니다. 여러분들의 프로젝트 등에 사용해야만 하는 것들입니다.
다음 시간에는 다양한 딥러닝 소프트웨어 패키지들이 대해서 조금 더 자세히 배워보도록 하겠습니다.